﻿-- Author      : Kurapica

--------------------------
-- ItemButton	        --
--------------------------
do
	-- Check Version
	local version = 1

	if not IGAS:RegisterFile("IGAS.GUI.Widget.ItemButton", version) then
		return
	end

	local getmetatable = getmetatable
	local pairs = pairs
	local ipairs = ipairs
	local type = type
	local error = error
	local CreateFrame = IGAS.GUI.CreateFrame
	
	local _GUI = IGAS.GUI
	local _Widget = IGAS.GUI.Widget
	local _BaseFunc = IGAS.GUI.Base.Func
	local _PropertyType = IGAS.GUI.Base.PropertyType
	local _Enum = IGAS.GUI.Base.Enum
	
	local GameTooltip = _BaseFunc.GetWrapper(GameTooltip)
	
	------------------------------------------------------
	---------------       ItemList           ---------------
	------------------------------------------------------
	local ItemList
	local ItemSize = 37
	do		
		local _WidgetName = "ItemList"
		local _Base = "Frame"
		local _ItemListContainer = CreateFrame("Frame", "IGASGUI_ListContainer")
		_ItemListContainer.__ShowList = _ItemListContainer.__ShowList or nil
		
		-- Scripts		
		local function OnShow(self)
			self:GetChild("Timer").Interval = 2
			
			if _ItemListContainer.__ShowList and _ItemListContainer.__ShowList ~= self then
				_ItemListContainer.__ShowList.Visible = false
			end
			
			_ItemListContainer.__ShowList = self
		end
		
		local function OnHide(self)
            if _ItemListContainer.__ShowList and _ItemListContainer.__ShowList == self then
				_ItemListContainer.__ShowList = nil
			end
			
			self:GetChild("Timer").Interval = 0
		end
		
		local function OnTimer(self)
			self.Interval = 0
			self.Parent.Visible = false
		end
		
		local function OnEnter(self)
			self:GetChild("Timer").Interval = 0
		end
		
		local function OnLeave(self)
			self:GetChild("Timer").Interval = 2
		end
		
		local function Item_OnEnter(self)
			self.Parent:Fire("OnEnter")
		end
		
		local function Item_OnLeave(self)
			self.Parent:Fire("OnLeave")
		end
		
		local function Item_OnClick(self)
            self.Parent:Fire("OnClick", self.Item)
			self.Parent.Visible = false
		end
		
		local function makePosition(self, start, count)
			local btn, locX, locY
			local i, maxC = start, start + (count or 0)
			
			btn = self:GetChild("ItemButton"..i)
			
			while (not count or i < maxC) and btn do
				btn = self:GetChild("ItemButton"..i)
				if btn then
					if self.__Direction == "TOP" then
						locX = 0
						locY = ItemSize * i
					elseif self.__Direction == "BOTTOM" then
						locX = 0
						locY = - ItemSize * i
					elseif self.__Direction == "LEFT" then
						locX = - ItemSize * i
						locY = 0
					elseif self.__Direction == "RIGHT" then
						locX = ItemSize * i
						locY = 0
					end
					btn:ClearAllPoints()
					btn:SetPoint(self.__Direction, self, self.__Direction, locX, locY)
				end
				i = i + 1
				btn = self:GetChild("ItemButton"..i)
			end
		end
		
		local function setItem(self, index, link)
			local btn
			btn = self:GetChild("ItemButton"..index)
			
			if not btn then
				btn = CreateFrame("ItemButton", "ItemButton"..index, self)
				
				btn.ShowItemCount = false
				btn.ShowItemName = false
				
				btn.OnEnter = Item_OnEnter
				btn.OnLeave = Item_OnLeave
				btn.OnClick = Item_OnClick
				
				makePosition(self, index, 1)
			end
			
			btn.Item = link
			btn.Visible = true
		end
		
		local function makeList(self)
			local index = 1
			local item
			
			if self.__FilterFunc then
				-- Set List
				--- Check Inventory Item
				for slot = 0, 19 do
					item = GetInventoryItemLink(self.__Unit, slot)
					if item and (self.__AllowSameItem or (not self:HasItem(item))) and self.__FilterFunc(self, item, -1, slot) then
						setItem(self, index, item)
						index = index + 1
					end
				end
				
				-- Check Container Item
				if self.__Unit == "player" then
					for i=0,NUM_BAG_FRAMES do
						for j=1,GetContainerNumSlots(i) do
							item = GetContainerItemLink(i,j)
							if item and (self.__AllowSameItem or (not self:HasItem(item))) and self.__FilterFunc(self, item, -1, slot) then
								setItem(self, index, item)
								index = index + 1
							end
						end
					end
				end
				
				-- A nil ItemButton
				if self.__ShowNilButton then
					setItem(self, index, nil)
					index = index + 1
				end
				
				-- Hide no-use ItemButton
				while self:GetChild("ItemButton"..index) do
					self:GetChild("ItemButton"..index).Item = nil
					self:GetChild("ItemButton"..index).Visible = false
					index = index + 1
				end
			else
				-- Hide List
				if self.__ShowNilButton then
					setItem(self, index, nil)
					index = index + 1
				end				
				
				-- Hide no-use ItemButton
				while self:GetChild("ItemButton"..index) do
					self:GetChild("ItemButton"..index).Item = nil
					self:GetChild("ItemButton"..index).Visible = false
					index = index + 1
				end
			end
		end
				
		-- ScriptType
		local _ScriptType = {
            ["OnClick"] = true,
		}
	    
		-- FuncProxy
		local _FuncProxy = {
			-- Refresh
			["Refresh"] = function(self)
				makeList(self)
			end,
			-- AddItem
			["Add"] = function(self, item)
				local index = 1
				local btn
				
				btn = self:GetChild("ItemButton"..index)
				while btn and btn.Visible and btn.Item do
					index = index + 1
					btn = self:GetChild("ItemButton"..index)
				end
				
				setItem(self, index, item)
				
				-- A nil ItemButton
				if self.__ShowNilButton then
					setItem(self, index, nil)
					index = index + 1
				end
			end,
			-- RemoveItem
			["Remove"] = function(self, item)
				local index = 1
				local btn, nextBtn
				
				if not item then
					return
				end
				
				btn = self:GetChild("ItemButton"..index)
				while btn and btn.Visible and btn.Item ~= item do
					index = index + 1
					btn = self:GetChild("ItemButton"..index)
				end
				
				if btn and btn.Item == item then
					index = index + 1
					nextBtn = self:GetChild("ItemButton"..index)
					while nextBtn and nextBtn.Visible do
						btn.Item = nextBtn.Item
						btn = nextBtn
						index = index + 1
						nextBtn = self:GetChild("ItemButton"..index)
					end
					btn.Item = nil
					btn.Visible = false
				end
			end,
			-- ClearItem
			["Clear"] = function(self)
				local index = 1
				local btn
				
				btn = self:GetChild("ItemButton"..index)
				while btn and btn.Visible do
					btn.Item = nil
					btn.Visible = false
					
					index = index + 1
					btn = self:GetChild("ItemButton"..index)
				end
				
				-- A nil ItemButton
				if self.__ShowNilButton then
					setItem(self, 1, nil)
				end
			end,
			-- HasItem
			["HasItem"] = function(self, item)
				local index = 1
				local btn, nextBtn
				
				if not item then
					return
				end
				
				btn = self:GetChild("ItemButton"..index)
				while btn and btn.Visible and btn.Item ~= item do
					index = index + 1
					btn = self:GetChild("ItemButton"..index)
				end
				
				if btn and btn.Item == item then
					return true
				else
					return false
				end
			end,
	    }
	    
		-- Property
		local _Property = {
			-- Filter
			["Filter"] = {
				["Set"] = function(self, func)
                    if func and type(func) ~= "function" then
						error("The parameter must be a function.", 2)
					end
					self.__FilterFunc = func
                end,
                
                ["Get"] = function(self)
                    return self.__FilterFunc
                end,
                
                ["Type"] = _PropertyType.Function,
			},
			-- Direction
			["Direction"] = {
				["Set"] = function(self, dir)
					local chk = false
					
					for i, v in ipairs(_Enum.Direction) do
						if v == dir then
							chk = true
							break
						end
					end
					if not chk then
						error("The Direction is incorrect.", 2)
					end
					self.__Direction = dir
					
					makePosition(self, 1)
                end,
                
                ["Get"] = function(self)
                    return self.__Direction
                end,
                
                ["Type"] = _PropertyType.Direction,
			},
			-- Unit
			["Unit"] = {
				["Set"] = function(self, unit)
					self.__Unit = unit
                end,
                
                ["Get"] = function(self)
					return self.__Unit
                end,
                
                ["Type"] = _PropertyType.String,
			},
			-- ShowNilButton
			["ShowNilButton"] = {
				["Set"] = function(self, flag)
					self.__ShowNilButton = (flag and true) or false
                end,
                
                ["Get"] = function(self)
					return (self.__ShowNilButton and true) or false
                end,
                
                ["Type"] = _PropertyType.Boolean,
			},
			-- AllowSameItem
			["AllowSameItem"] = {
				["Set"] = function(self, flag)
					self.__AllowSameItem = (flag and true) or false
                end,
                
                ["Get"] = function(self)
					return (self.__AllowSameItem and true) or false
                end,
                
                ["Type"] = _PropertyType.Boolean,
			},
		}
		
	    -- New      
	    local _New = function(parent)		
			local frame = CreateFrame("Frame", nil, _ItemListContainer)
			
			-- Remove it make it free to set name
            _ItemListContainer:RemoveChild(frame)
			
			frame.FrameStrata = "TOOLTIP"
			frame.Height = ItemSize
			frame.Width = ItemSize
            frame.Visible = false
			
			frame.__Direction = "BOTTOM"
			frame.__Unit = "player"
			frame.__ShowNilButton = true
			
			-- Timer
			local timer = CreateFrame("Timer", "Timer", frame)
			timer.Interval = 0
			timer.OnTimer = OnTimer
			
			frame:StackScript("OnShow", OnShow)
			frame:StackScript("OnHide", OnHide)
			frame:StackScript("OnEnter", OnEnter)
			frame:StackScript("OnLeave", OnLeave)
			
	        return frame
	    end
		
	    local _WidgetInfo = {
	        ["WidgetName"] = _WidgetName,
	        ["Base"] = _Base,
	        ["FuncProxy"] = _FuncProxy,
	        ["Property"] = _Property,
	        ["ScriptType"] = _ScriptType,
	        ["New"] = _New,
			["NotChild"] = true,
	    }
    
		ItemList = _GUI.NewWidget(_WidgetInfo)
        --_Widget[_WidgetName] = ItemList
	end
	
	------------------------------------------------------
	---------------       ItemButton          ------------
	------------------------------------------------------
	local _WidgetName = "ItemButton"
	local _Base = "Button"

	-- Script
	-- OnClick Script
	local function OnClick(self, ...)		
		if self.__ItemLink then
			if ( IsModifiedClick() ) then
				return HandleModifiedItemClick(self.__ItemLink)
			end
		end
		
		if self:GetChild("ItemList") then
			self:GetChild("ItemList").Visible = not self:GetChild("ItemList").Visible
			return
		end		
	end
		
	local function OnEnter(self, ...)		
		if self.__ItemLink then
			GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
			GameTooltip:SetHyperlink(self.__ItemLink)
			GameTooltip:Show()
		end
	end
		
	local function OnLeave(self, ...)		
		GameTooltip:ClearLines()
		GameTooltip:Hide()
	end
    
	local function OnHide(self, ...)		
		if self:GetChild("ItemList") and self:GetChild("ItemList").Visible then
			self:GetChild("ItemList"):Hide()
		end
	end
	
	local function SetItemTexture(self, texture)
		if ( texture ) then
			self:GetChild("Icon"):Show()
		else
			self:GetChild("Icon"):Hide()
		end
		self:GetChild("Icon"):SetTexture(texture)
	end
	
	local function SetItemName(self, name)
		self:GetChild("ItemName"):SetText(name)
	end
	
	local function SetItemCount(self, count)			
		if ( not count ) then
			count = 0
		end

		self.__Count = count
		if ( count > 1  ) then
			if ( count > 999 ) then
				count = "*"
			end
			self:GetChild("Count"):SetText(count)
			if self.__ShowItemCount then
				self:GetChild("Count"):Show()
			end
		else
			self:GetChild("Count"):Hide()
		end
	end
	
    local function list_OnClick(self, item)
        self.Parent.Item = item
    end
    
	local function GetItemList(self)
		if self:GetChild("ItemList") then
			return self:GetChild("ItemList")
		end
		local itemL = CreateFrame(ItemList, "ItemList", self)
		itemL:SetPoint("CENTER", self, "CENTER")
        itemL.OnClick = list_OnClick
        return itemL
	end
	
	-- ScriptType
	local _ScriptType = {
		["OnItemChanged"] = true,
	}	
	
	--	FuncProxy
	local _FuncProxy = {
		-- SetItemCount
		["SetItemCount"] = function(self, count)			
			SetItemCount(self, count)
		end,
		-- SetItemStock
		["SetItemStock"] = function(self, numInStock)			
			if ( not numInStock ) then
				numInStock = 0
			end

			self.__Stock = numInStock;
			if ( numInStock > 0 ) then
				self:GetChild("Stock"):SetFormattedText(MERCHANT_STOCK, numInStock);
				self:GetChild("Stock"):Show()
			else
				self:GetChild("Stock"):Hide()
			end
		end,
		-- SetItemTexture
		["SetItemTexture"] = function(self, texture)
			SetItemTexture(self, texture)
		end,
		-- SetItemTextureVertexColor
		["SetItemTextureVertexColor"] = function(self, r, g, b)			
			self:GetChild("Icon"):SetVertexColor(r, g, b)
		end,
		-- SetItemDesaturated
		["SetItemDesaturated"] = function(self, desaturated, r, g, b)
			local icon = self:GetChild("Icon")
			if ( not icon ) then
				return
			end
			local shaderSupported = icon:SetDesaturated(desaturated);

			if ( not desaturated ) then
				r = 1.0;
				g = 1.0;
				b = 1.0;
			elseif ( not r or not shaderSupported ) then
				r = 0.5;
				g = 0.5;
				b = 0.5;
			end
			
			icon:SetVertexColor(r, g, b)
		end,
		-- SetItemNormalTextureVertexColor
		["SetItemNormalTextureVertexColor"] = function(self, r, g, b)			
			self:GetChild("NormalTexture"):SetVertexColor(r, g, b);
		end,
		-- SetItemName
		["SetItemName"] = function(self, name)
			SetItemName(self, name)
		end,
		
		--- Special Item Set
		-- SetContainerItem
		["SetItem"] = function(self, link)
			local itemName, itemTexture, itemCount
			if not link then
				-- Clear
				self.__ItemLink = nil
				SetItemName(self, "")
				SetItemTexture(self, nil)
				if self.__ShowItemCount then
					SetItemCount(self, 0)
				end
				self:Fire("OnItemChanged")
				return
			end
			-- Set
			itemName, _, _, _, _, _, _, _, _, itemTexture = GetItemInfo(link)
			if itemName and link ~= self.__ItemLink then
				self.__ItemLink = link
				SetItemName(self, itemName)
				SetItemTexture(self, itemTexture)
				if self.__ShowItemCount then
					itemCount = GetItemCount(link, self.__BankItemIncluded)
					SetItemCount(self, itemCount)
				end
				self:Fire("OnItemChanged")
			else
				error("The parameter you passed in is not an item.", 2)
			end
		end,
		-- GetItemLink
		["GetItem"] = function(self)
			return self.__ItemLink
		end,
		--- Item List
		-- RefreshList
		["RefreshList"] = function(self, filterFunc)
			local list = GetItemList(self)
			
			if filterFunc and type(filterFunc) == "function" then
				list.Filter = filterFunc
			end
			list:Refresh()
		end,
		-- AddListItem
		["AddListItem"] = function(self, item)
			local list = GetItemList(self)
			
			list:Add(item)
		end,
		-- RemoveListItem
		["RemoveListItem"] = function(self, item)			
			local list = GetItemList(self)
			
			list:Remove(item)
		end,
		-- ClearList
		["ClearList"] = function(self)					
			local list = GetItemList(self)
			
			list:Clear()
		end,
		-- RemoveList
		["RemoveList"] = function(self)
			if self:GetChild("ItemList") then
				self:GetChild("ItemList"):Dispose()
			end
		end,
	}

	--	Property
	local _Property = {
		-- ShowItemCount
		["ShowItemCount"] = {
			["Set"] = function(self, flag)
				self.__ShowItemCount = (flag and true) or false
			end,
			
			["Get"] = function(self)
				return (self.__ShowItemCount and true) or false
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
		-- BankItemIncluded
		["BankItemIncluded"] = {
			["Set"] = function(self, flag)
				self.__BankItemIncluded = (flag and true) or false
			end,
			
			["Get"] = function(self)
				return (self.__BankItemIncluded and true) or false
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
		-- ItemCount
		["ItemCount"] = {
			["Set"] = function(self, count)
				self:SetItemCount(count)
			end,
			
			["Get"] = function(self)
				return self.__Count or 0
			end,
			
			["Type"] = _PropertyType.Number,
		},
		-- ItemStock
		["ItemStock"] = {
			["Set"] = function(self, numInStock)
				self:SetItemStock(numInStock)
			end,
			
			["Get"] = function(self)
				return self.__Stock or 0
			end,
			
			["Type"] = _PropertyType.Number,
		},
		-- ItemTexture
		["ItemTexture"] = {
			["Set"] = function(self, texture)				
				self:SetItemTexture(texture)
			end,
			
			["Type"] = _PropertyType.Texture,
		},
		-- ShowItemName
		["ShowItemName"] = {
			["Set"] = function(self, flag)
				self.__ShowItemName = (flag and true) or false
				self:GetChild("ItemName").Visible = self.__ShowItemName
			end,
			
			["Get"] = function(self)
				return (self.__ShowItemName and true) or false
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
		-- ItemName
		["ItemName"] = {
			["Set"] = function(self, name)				
				self:SetItemName(name)
			end,
			
			["Type"] = _PropertyType.String,
		},
		-- Item
		["Item"] = {
			["Set"] = function(self, link)
				self:SetItem(link)
			end,
			
			["Get"] = function(self)
				return self:GetItem()
			end,
			
			["Type"] = _PropertyType.String,
		},
		--- Item List
		-- Direction
		["ListDirection"] = {
			["Set"] = function(self, dir)
				local list = GetItemList(self)
				
				list.Direction = dir
			end,
			
			["Get"] = function(self)
				local list = GetItemList(self)
				
				return list.Direction
			end,
			
			["Type"] = _PropertyType.Direction,
		},
		-- Unit
		["ListUnit"] = {
			["Set"] = function(self, unit)
				local list = GetItemList(self)
				
				list.Unit = unit
			end,
			
			["Get"] = function(self)
				local list = GetItemList(self)
				return list.Unit
			end,
			
			["Type"] = _PropertyType.String,
		},
		-- ListShowNilButton
		["ListShowNilButton"] = {
			["Set"] = function(self, flag)
				local list = GetItemList(self)
				list.ShowNilButton = flag
			end,
			
			["Get"] = function(self)
				local list = GetItemList(self)
				return list.ShowNilButton
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
	}

	local function _New(parent)		
        local btn = CreateFrame("Button", nil, parent)
        
        btn.Width = 37
        btn.Height = 37
        
		-- Texture
        local t = CreateFrame("Texture", "NormalTexture", btn)
        t:SetTexture("Interface\\Buttons\\UI-Quickslot2")
        t.Height = 64
        t.Width = 64
        t:SetPoint("CENTER", btn, "CENTER", 0, -1)
        btn:SetNormalTexture(t)
        btn:SetPushedTexture("Interface\\Buttons\\UI-Quickslot-Depress")
        btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
        t = btn:GetHighlightTexture()
        t:SetBlendMode("ADD")
        
		-- Icon
        local icon = CreateFrame("Texture", "Icon", btn, "BORDER")
        icon:SetAllPoints(btn)
        
		-- Count
        local count = CreateFrame("FontString", "Count", btn, "BORDER", "NumberFontNormal")
        count.JustifyH = "RIGHT"
        count.Visible = false
        count:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -5, 2)
        
        local stock = CreateFrame("FontString", "Stock", btn, "BORDER", "NumberFontNormalYellow")
        stock.JustifyH = "LEFT"
        stock.Visible = false
        stock:SetPoint("TOPLEFT", btn, "TOPLEFT", 0, -2)
        
		-- ItemName
		local itemName = CreateFrame("FontString", "ItemName", btn, "OVERLAY", "GameFontHighlightSmallOutline")
		itemName.Width = 36
		itemName.Height = 10
		itemName.Visible = false
        itemName:SetPoint("BOTTOM", btn, "BOTTOM", 0, 2)
		
		btn.__ShowItemCount = true
		btn.__ShowItemName = false
		
		btn:StackScript("OnClick", OnClick)
		btn:StackScript("OnEnter", OnEnter)
		btn:StackScript("OnLeave", OnLeave)
        btn:StackScript("OnHide", OnHide)
		
		return btn		
	end	

	-- Register
	local _WidgetInfo = {
		["WidgetName"] = _WidgetName,
		["Base"] = _Base,
		["FuncProxy"] = _FuncProxy,
		["Property"] = _Property,
		["ScriptType"] = _ScriptType,
		["New"] = _New,
	}

	_Widget[_WidgetName] = _GUI.NewWidget(_WidgetInfo)
end
